#include <stdint.h>

enum BombSignals {
    UP_SIG,
    DOWN_SIG,
    ARM_SIG,
    TICK_SIG,
};

enum BombStates {
    SETTINGS_STATE,
    TIMING_STATE,
};

typedef struct Event {
    uint16_t sig; // signal
} Event;

typedef struct TickEvt {
    Event super;
    uint8_t fine_time;
} TickEvt;

typedef struct Bomb {
    uint8_t state;
    uint8_t timeout;
    uint8_t defuse;
    uint8_t code;
} Bomb;

#define INITIAL_TIMEOUT (30U)

// void Fsm_init(StateMachine * const me);
// void Fsm_dispatch(StateMachine * const me, Event const * const e);
void Bomb_ctor(Bomb * const me);
void Bomb_init(Bomb * const me);
void Bomb_dispatch(Bomb * const me, Event const * const e);

void BSP_display(uint8_t timeout);
void BSP_boom(void);

void Bomb_ctor(Bomb * const me) {
    me->defuse = 0x55;
}

void Bomb_init(Bomb * const me) {
    me->timeout = INITIAL_TIMEOUT;
    me->state = SETTINGS_STATE;
}

void Bomb_dispatch(Bomb * const me, Event const * const e) {
    switch (me->state) {
    case (uint8_t)SETTINGS_STATE:
        switch (e->sig) {
        case UP_SIG:
            if (me->timeout < 60) {
                ++me->timeout;
                BSP_display(me->timeout);
            }
            break;
        case DOWN_SIG:
            if (me->timeout > 1) {
                --me->timeout;
                BSP_display(me->timeout);
            }
            break;
        case ARM_SIG:
            me->code = 0;
            me->state = TIMING_STATE;
            break;
        }
        break;

    case (uint8_t)TIMING_STATE:
        switch (e->sig) {
        case UP_SIG:
            me->code <<= 1;
            me->code |= 1;
            break;
        case DOWN_SIG:
            me->code <<= 1;
            break;
        case ARM_SIG:
            if (me->defuse == me->code) {
                me->state = SETTINGS_STATE;
            }
            break;
        case TICK_SIG:
            if (((TickEvt const * const)e)->fine_time == 0) {
                --me->timeout;
                BSP_display(me->timeout);
                if (me->timeout == 0) {
                    BSP_boom();
                }
            }
            break;
        }
        break;
    }
}
